﻿using System.Linq;
using NDBGen.Descriptors.Columns.DataTypes;
using NDBGen.Plugins.DataAccess;

namespace NDBGen.Plugins.Descriptors.Columns.DataTypes
{
    public abstract class DotNetColumnDataTypeCodeGeneratorBase<T> : DotNetColumnCodeGeneratorBase, IColumnDataTypeCodeSnippetGenerator
        where T : IColumnDataTypeDescriptor
    {
        protected Table Table { get; private set; }

        protected Column Column { get; private set; }

        protected new T Descriptor
        {
            get { return (T)base.Descriptor; }
        }

        protected virtual void WriteAttributes(IIndentedTextWriter writer)
        {
            var dataTypeAttributes = this.GetAttributes();

            var tokenGenerators = (
                from token in this.Column.Descriptors.SortOrdered()                
                select (IDotNetColumnCodeGenerator)this.GetGeneratorForDescriptor(token)).ToArray();

            var tokenAttributes =
                from tokenGenerator in tokenGenerators                
                from attribute in tokenGenerator.GetAttributes()
                select attribute;

            var columnAttributeProperties = (
                from tokenGenerator in tokenGenerators
                from attributeProperty in tokenGenerator.GenerateColumnAttributeProperties()
                select attributeProperty).Union(this.GenerateColumnAttributeProperties());

            foreach (var attribute in dataTypeAttributes.Union(tokenAttributes).SortOrdered())
            {
                writer.WriteLine(attribute);
            } 

            var columnAttribute = ColumnMetadataHelper.CreateColumnAttribute(this.Descriptor.Column.Name, columnAttributeProperties.ToArray());
            writer.WriteLine(columnAttribute);
        }

        protected abstract void WriteProperty(IIndentedTextWriter writer);

        void IColumnDataTypeCodeSnippetGenerator.WriteProperty(IIndentedTextWriter writer)
        {
            this.WriteAttributes(writer);
            this.WriteProperty(writer);
        }

        protected virtual void Init(IPluginData pluginData, IColumnDataTypeDescriptor descriptor)
        {
            base.Init(pluginData, descriptor);
            this.Column = descriptor.Column;
            this.Table = descriptor.Table;
        }

        void IGenerator<IColumnDataTypeDescriptor>.Init(IPluginData pluginData, IColumnDataTypeDescriptor descriptor)
        {
            this.Init(pluginData, descriptor);            
        }
    }
}